package org.linlinjava.litemall.wx.service;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaSubscribeMessage;
import me.chanjar.weixin.common.error.WxErrorException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.linlinjava.litemall.core.system.SystemConfig;
import org.linlinjava.litemall.core.task.TaskService;
import org.linlinjava.litemall.core.util.DateTimeUtil;
import org.linlinjava.litemall.core.util.ResponseUtil;
import org.linlinjava.litemall.db.domain.*;
import org.linlinjava.litemall.db.service.*;
import org.linlinjava.litemall.db.util.*;
import org.linlinjava.litemall.wx.task.SpellUnpaidTask;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static org.linlinjava.litemall.wx.util.WxResponseCode.ORDER_INVALID;
import static org.linlinjava.litemall.wx.util.WxResponseCode.ORDER_UNKNOWN;

@Service
public class WxSpellService {
    private final Log logger = LogFactory.getLog(WxSpellService.class);
    @Autowired
    private LitemallSpellService litemallSpellService;
    @Autowired
    private LitemallUserService litemallUserService;
    @Autowired
    private LitemallGoodsService litemallGoodsService;
    @Autowired
    private LitemallOrderService orderService;
    @Autowired
    private LitemallOrderGoodsService orderGoodsService;
    @Autowired
    private LitemallUserService userService;
    @Autowired
    private WxMaService wxMaService;
    @Autowired
    private TaskService taskService;
    @Autowired
    private WxBenefitService wxBenefitService;
    @Autowired
    private LitemallGoodsService goodsService;

    /**
     * 拼单信息，结束时间，商品等
     * @param orderId
     * @return
     */
    public Map<String, Object> spellByOrder(Integer userId, Integer orderId) {
        if (userId == null) {
            return null;
        }
        LitemallOrder order = orderService.findById(orderId);
        LitemallSpell spell = litemallSpellService.queryByOrderId(order.getId());
        if (spell == null) {
            return null;
        }
        LitemallOrderGoods orderGoods = orderGoodsService.queryOneGoodsByOid(order.getId());
        Map<String, Object> result = new HashMap<>();
        result.put("picUrl", orderGoods.getPicUrl());
        result.put("id", orderId);
        result.put("goodsId", orderGoods.getGoodsId());
        result.put("goodsName", orderGoods.getGoodsName());
        result.put("spellId", spell.getId());
        result.put("leftTime", DateTimeUtil.leftTime(spell.getExpireTime()));
        return result;
    }

    /**
     * 拼单信息，结束时间，商品等
     * @param orderId
     * @return
     */
    public Map<String, Object> detailByOrder(Integer orderId) {
        LitemallSpell spell = litemallSpellService.queryByOrderId(orderId);
        if (spell == null) {
            return null;
        }
//        Map<String, Object> result = new HashMap<>();
        Map<String, Object> result = getInvolved(spell);
        result.put("spellId", spell.getId());
        result.put("reducePrice", spell.getReducePrice());
        result.put("isCreator", spell.getSpellId().equals(0));
        result.put("status", spell.getStatus());
        return result;
    }

    /**
     * 拼单详情
     *
     * @param id
     * @return
     */
    public Object detail(Integer userId, Integer id) {
        if (userId == null) {
            return ResponseUtil.unlogin();
        }
        LitemallSpell spell = litemallSpellService.queryById(userId, id);
        if (spell == null) {
            return ResponseUtil.fail();
        }
        LitemallOrder order = orderService.findById(spell.getOrderId());
        if (null == order) {
            return ResponseUtil.fail(ORDER_UNKNOWN, "订单不存在");
        }
        if (!order.getUserId().equals(userId)) {
            return ResponseUtil.fail(ORDER_INVALID, "不是当前用户的订单");
        }

        return ResponseUtil.ok(info(order, spell));
    }

    /**
     * 拼单具体详情
     */
    public Map<String, Object> info(LitemallOrder order, LitemallSpell spell) {
        Map<String, Object> orderVo = new HashMap<String, Object>();
        orderVo.put("id", order.getId());
        orderVo.put("orderSn", order.getOrderSn());
        orderVo.put("goodsPrice", order.getGoodsPrice());
        orderVo.put("freightPrice", order.getFreightPrice());
        orderVo.put("actualPrice", order.getActualPrice());
        LitemallOrderGoods orderGoods = orderGoodsService.queryOneGoodsByOid(order.getId());
        Map<String, Object> result = new HashMap<>();
        result.put("orderInfo", orderVo);
        result.put("orderGoods", orderGoods);
        Map<String, Object> involved = getInvolved(spell);
        result.put("creator", involved.get("creator"));
        result.put("joiners", involved.get("joiners"));
        result.put("spell", spell);
        result.put("leftTime", DateTimeUtil.leftTime(spell.getExpireTime()));
        return result;
    }

    /**
     * 获取参与者
     * @param spell
     * @return
     */
    public Map<String, Object> getInvolved(LitemallSpell spell) {
        UserVo creator = userService.findUserVoById(spell.getCreatorUserId());
        List<UserVo> joiners = new ArrayList<>();
        joiners.add(creator);
        if (spell.getSpellId() == 0) { // 本身是发起者
            LitemallSpell spellJoiner = litemallSpellService.queryJoinRecord(spell.getId());
            if (spellJoiner != null) {
                UserVo joiner = userService.findUserVoById(spellJoiner.getUserId());
                joiners.add(joiner);
            }
        } else { // 本身是一个参与者
            UserVo joiner = userService.findUserVoById(spell.getUserId());
            joiners.add(joiner);
        }
        Map<String, Object> result = new HashMap<>();
        result.put("creator", creator);
        result.put("joiners", joiners);
        return result;
    }

    /**
     * 发起拼单
     *
     * @param userId
     * @param orderId
     * @return
     */
    public LitemallSpell open(Integer userId, Integer orderId) {
        LitemallSpell spell = new LitemallSpell();

        List<LitemallOrderGoods> orderGoods = orderGoodsService.queryByOid(orderId);
        if (orderGoods.size() != 1) {
            throw new RuntimeException("出现严重错误");
        }
        Integer goodsId = orderGoods.get(0).getGoodsId();
        LitemallGoods goods = litemallGoodsService.findById(goodsId);

        spell.setOrderId(orderId);
        spell.setUserId(userId);
        spell.setGoodsId(goodsId);
        spell.setCreatorUserId(userId);
        spell.setReducePrice(goods.getSpellReduce().multiply(new BigDecimal(orderGoods.get(0).getNumber())));
        spell.setStatus(SpellConstant.STATUS_WAIT_IN);
        int lastTime = SystemConfig.getSpellUnpaid() * 60; // 持续时间(秒数)
        lastTime += 30; // 预留程序处理时间
        LocalDateTime expireTime = LocalDateTime.now().plus(Long.valueOf(lastTime), ChronoUnit.SECONDS);
        spell.setExpireTime(expireTime);
        litemallSpellService.create(spell);
        // 增加超时任务
        taskService.addTask(new SpellUnpaidTask(spell.getId()));
        return spell;
    }

    /**
     * 参与拼单, 出错返回空
     *
     * @param userId
     * @param orderId
     * @return
     */
    public Integer involve(LitemallSpell creator, Integer userId, Integer orderId) {
        return involve(creator, userId, orderId, null);
    }

    /**
     * 参与拼单, 出错返回空
     *
     * @param userId
     * @param orderId
     * @return
     */
    @Transactional
    public Integer involve(LitemallSpell creator, Integer userId, Integer orderId, Integer goodsId) {
        if (!SpellConstant.STATUS_WAIT_IN.equals(creator.getStatus())) {
            return null;
        }
        if (goodsId != null && !creator.getGoodsId().equals(goodsId)) {
            return null;
        }
        LitemallOrder creatorOrder = orderService.findById(creator.getOrderId());
        if (creatorOrder == null) {
            return null;
        }
        creatorOrder.setSpellStatus(OrderSpellConstant.STATUS_YES);
        if (orderService.updateWithOptimisticLocker(creatorOrder) == 1) {
            creator.setStatus(SpellConstant.STATUS_WAIT_PAY);
            litemallSpellService.updateById(creator); // 占坑
            LitemallSpell spell = new LitemallSpell();
            spell.setOrderId(orderId);
            spell.setUserId(userId);
            spell.setGoodsId(creator.getGoodsId());
            spell.setSpellId(creator.getId());
            spell.setExpireTime(creator.getExpireTime());
            spell.setCreatorUserId(creator.getCreatorUserId());
            spell.setReducePrice(creator.getReducePrice());
            spell.setStatus(SpellConstant.STATUS_WAIT_PAY);
            return litemallSpellService.create(spell);
        } else {
            System.out.println("拼单失败，已被抢占");
            // 已被抢占
            return null;
        }
    }

    /**
     * 结束参与拼单, 出错返回空
     *
     * @param orderId
     * @return
     */
    @Transactional
    public void breakInvolve(Integer orderId) {
        LitemallSpell involver = litemallSpellService.queryInvolveByOrderId(orderId); // 参与者
        if (involver == null) { //未参与拼单
            return;
        }
        if (!SpellConstant.STATUS_WAIT_PAY.equals(involver.getStatus())) {
            logger.error("当前取消订单所参与拼单活动已结束或未开启");
            return;
        }
        LitemallSpell creator = litemallSpellService.findById(involver.getSpellId());  // 发起者
        if (!SpellConstant.STATUS_WAIT_PAY.equals(creator.getStatus())) {
            logger.error("出现错误，拼单已结束或未开启");
            return;
        }
        LitemallOrder creatorOrder = orderService.findById(creator.getOrderId());
        if (creatorOrder == null) {
            return;
        }
        creatorOrder.setSpellStatus(OrderSpellConstant.STATUS_WAIT);
        if (orderService.updateWithOptimisticLocker(creatorOrder) == 1) {
            creator.setStatus(SpellConstant.STATUS_WAIT_IN);
            litemallSpellService.updateById(creator); // 清坑
            involver.setStatus(SpellConstant.STATUS_FAIL);
            litemallSpellService.updateById(involver); // 拼单参与失败(超时未付款)
        } else {
            System.out.println("拼单释放失败");
            return;
        }
    }

    /**
     * 成功拼单并返钱(返回余额)
     */
    @Transactional
    @Async
    public void finish(Integer orderId) {
        LitemallSpell involver = litemallSpellService.queryInvolveByOrderId(orderId); //查询拼单参与记录
        // 查询发起订单
        if (involver == null) {
            return;
        }
        if (involver.getUserId().equals(involver.getCreatorUserId())) { // 基本上不会发生
            logger.error("出现严重错误: 拼单两人相同");
            return;
        }
        Integer creatorId = involver.getSpellId();
        LitemallSpell creator = litemallSpellService.findById(creatorId); // 查询拼单发起记录
        if (!creator.getGoodsId().equals(involver.getGoodsId())) {// 基本上不会发生
            logger.error("出现严重错误:拼单商品不一致");
            return;
        }
        LitemallOrder creatorOrder = orderService.findById(creator.getOrderId());
        involver.setStatus(SpellConstant.STATUS_SUCCESS);
        involver.setEndTime(LocalDateTime.now());
        creator.setStatus(SpellConstant.STATUS_SUCCESS);
        creator.setEndTime(LocalDateTime.now());
        litemallSpellService.updateById(involver);
        litemallSpellService.updateById(creator);
        Integer creatorUserId = creator.getCreatorUserId();
        // 记录并奖励用户余额
        wxBenefitService.spell(creatorUserId, involver.getUserId(), creator.getId().toString(), creator.getReducePrice(), creatorOrder.getActualPrice());
        // 取消拼单超时任务
        taskService.removeTask(new SpellUnpaidTask(creator.getId()));
        // 发送消息
        sendMessage(creator.getCreatorUserId(), creator.getReducePrice(), involver.getUserId(), creator.getGoodsId());
    }

    /**
     * 拼单失败
     *
     * @param spellId
     */
    public void fail(Integer spellId) {
        LitemallSpell creator = litemallSpellService.findById(spellId);
        if (!creator.getSpellId().equals(0)) { // 非创建者不处理
            return;
        }
        if (creator.getStatus().equals(SpellConstant.STATUS_FAIL) || creator.getStatus().equals(SpellConstant.STATUS_SUCCESS)) { // 拼单结束
            return;
        }
        litemallSpellService.fail(creator);
    }

    /**
     * 给开团人推送消息
     *
     * @param userId
     */
    public void sendMessage(Integer userId, BigDecimal reducePrice, Integer involveId, Integer goodsId) {
        LitemallUser user = userService.findById(userId);
        LitemallUser involver = userService.findById(involveId);
        LitemallGoods goods = goodsService.findById(goodsId);
        WxMaSubscribeMessage message = new WxMaSubscribeMessage();
        message.setToUser(user.getWeixinOpenid());
        message.setTemplateId("eEkDOnf36NLNnQkzIy_2QyaGlNzOci-Il3zeR70eUuw");
        ArrayList<WxMaSubscribeMessage.Data> data = new ArrayList<>();
        WxMaSubscribeMessage.Data item1 = new WxMaSubscribeMessage.Data();
        item1.setName("thing1");
        item1.setValue(goods.getName());
        data.add(item1);
        WxMaSubscribeMessage.Data item2 = new WxMaSubscribeMessage.Data();
        item2.setName("amount3");
        item2.setValue(reducePrice.toString());
        data.add(item2);
        WxMaSubscribeMessage.Data item3 = new WxMaSubscribeMessage.Data();
        item3.setName("thing2");
        item3.setValue(user.getNickname()+','+involver.getNickname());
        data.add(item3);
        message.setData(data);
        try {
            wxMaService.getMsgService().sendSubscribeMsg(message);
        } catch (WxErrorException e) {
            e.printStackTrace();
            System.out.println(e);
        }
    }
}
